home *** CD-ROM | disk | FTP | other *** search
- /*
- * Gnuplotio - A procedural interface to Gnuplot which turns
- * Gnuplot into an expression evaluator.
- *
- * NOTE: gnuplot (verision 3.0 or higher) must have the "table" terminal type.
- *
- * Written by Kevin Russo SFA, Inc/US Naval Research Lab, Code 5133
- * March 1991
- *
- * Future fix: all reads should be non-blocking and return the number
- * of chars read.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #ifdef MSDOS
- #include <io.h> /* access */
- #include <sys\types.h>
- #else
- #include <unistd.h> /* access */
- #include <sys/types.h>
- #endif
- #include "gnuplotio.h"
- #include "popen.h"
- #include "util.h"
-
- /*
- * openGnuplot(NULL)
- * openGnuplot("")
- * Searches your $PATH for "gnuplot"
- *
- * openGnuplot("gnuplot3.1")
- * Searches your $PATH for "gnuplot3.1"
- *
- * openGnuplot("/obscure/gnuplot")
- * Runs /obscure/gnuplot if it exists and is executable
- *
- * open 3 pipes to a gnuplot process. (stdin, stdout, stderr)
- *
- * popen_ioe() is like popen(3) but it opens 3 pipes.
- *
- * Returns:
- * GNUPLOT handle
- */
- GNUPLOT *openGnuplot(const char *gnuplotpath)
- {
- GNUPLOT *gp;
- char *programpath;
-
- /* This code guarantees that popen_ioe() can't fail...
- there's no good way to recover from popen() failing
- */
- if (gnuplotpath == NULL || *gnuplotpath == '\0')
- { /* see if popen("gnuplot") will work */
- programpath = "gnuplot";
- switch (can_run(programpath))
- {
- case 1:
- fprintf(stderr,"openGnuplot: %s is not executable\n",
- programpath);
- return NULL;
- /* NOTREACHED */
- break;
- case 2:
- fprintf(stderr,"openGnuplot: %s is not in $path\n",programpath);
- return NULL;
- /* NOTREACHED */
- break;
- }
- }
- else if (strchr(gnuplotpath, '/') == NULL)
- { /* see if popen(other_gnuplot_in_search_path) will work */
- programpath = gnuplotpath;
- switch (can_run(programpath))
- {
- case 1:
- fprintf(stderr,"openGnuplot: %s is not executable\n",
- programpath);
- return NULL;
- /* NOTREACHED */
- break;
- case 2:
- fprintf(stderr,"openGnuplot: %s is not in $path\n",programpath);
- return NULL;
- /* NOTREACHED */
- break;
- }
- }
- else
- { /* see if we can execute the path-qualified (ie has /) */
- programpath = gnuplotpath;
- if (access(programpath, X_OK) == -1)
- {
- fprintf(stderr,"openGnuplot: can't execute %s. Reason: %s\n",
- programpath, strerror(errno));
- return NULL;
- }
- }
-
- if ((gp = (GNUPLOT *) malloc(1 * sizeof(GNUPLOT))) == NULL)
- {
- fprintf(stderr,"openGnuplot: malloc failure.\n");
- return NULL;
- }
- /*
- if((gp->ptr = popen_ioe(programpath,"rwe")) == NULL) */
- if((gp->ptr = popen_rw(programpath)) == NULL)
- {
- /* can_run() above should catch any failure, so this
- shouldn't ever happen (famous last words) */
- fprintf(stderr,"openGnuplot: can't popen_ioe() to %s\n",
- programpath);
- return NULL;
- }
-
- setbuf(gp->ptr[1], (char *)0); /* no buffering on writes */
- /* setbuf(gp->ptr[2], (char *)0); /* no buffering on stderr reads */
- return gp;
- }
-
-
-
- /*
- * Write a command to the gnuplot process
- *
- * Returns:
- * 0 if any input arguments were invalid
- * 1 presume success writing to gnuplot
- */
- int writeGnuplot(GNUPLOT *gp, const char *command)
- {
- size_t len;
- char *cmd;
- #ifdef ACK_WORKING
- char ack[20];
- #endif /* ACK_WORKING */
-
- if (gp != NULL && gp->ptr[1] != NULL && command != NULL)
- {
- len = strlen(command);
- if (command[len-1] != '\n')
- {
- /* ensure that the command is new-line-terminated */
- cmd = (char *) malloc(len+2);
- strcpy(cmd, command);
- cmd[len] = '\n';
- cmd[len+1] = '\0';
- fputs(cmd,gp->ptr[1]);
- free(cmd);
- }
- else
- fputs(command,gp->ptr[1]);
- #ifdef ACK_WORKING
- /* block until gnuplot is finished */
- fgets(ack, sizeof(ack), gp->ptr[2]);
- printf("ack: \"%s\"\n",ack);
- #endif /* ACK_WORKING */
-
- return 1;
- }
-
- return -1;
- }
-
- /*
- * There are several ways to retrieve results from gnuplot:
- *
- * readErrorGnuplot()
- *
- * readGnuplot()
- * returns a line of gnuplot output
- *
- * readCurveHeadGnuplot()
- * returns the curve number and number of points. Use after writing
- * a "plot" or "splot" command to gnuplot.
- *
- * readCurve2Gnuplot()
- * fills the x[points], y[points] arrays with the points of a "plot"
- * command. The function returns the actual number of points read
- * (which could differ from npoints)
- *
- * readCurve3Gnuplot()
- * fills the x[points], y[points] z[npoints] arrays with the points
- * of a "splot" command. The function returns the actual number of
- * points read (which could differ from npoints)
- */
-
-
- /*
- * readErrorGnuplot
- *
- * Returns:
- * Number of bytes copied to the read buffer or
- * -1 if any input parameters were invalid
- *
- * Side Effects:
- * readbuf is filled with the error message, to a maximum of
- * sizeofreadbuf chars.
- *
- */
-
- int readErrorGnuplot(GNUPLOT *gp, char *readbuf, size_t sizeofreadbuf)
- {
- int n;
- if (gp != NULL && gp->ptr[2] != NULL && readbuf != NULL)
- {
- /* we don't want to block on this attempted read! */
- if (check_fd_for_reading(fileno(gp->ptr[2])))
- {
- /*printf("reading stderr\n");*/
- /*fgets(readbuf, sizeofreadbuf, gp->ptr[2]);*/
- /* unbuffered... get it all */
- n=read(fileno(gp->ptr[2]), readbuf,sizeofreadbuf);
- return n;
- }
- else
- return 0;
- }
-
- return -1;
- }
-
-
- /*
- * readGnuplot
- *
- * Fills readbuf with one line from gnuplot
- * This read blocks, so call it only when you expect some output
- *
- * Returns:
- * -1 if any input parameters were invalid
- * 1 presumed success
- *
- */
- int readGnuplot(GNUPLOT *gp, char *readbuf, size_t sizeofreadbuf)
- {
- if (gp != NULL && gp->ptr[0] != NULL && readbuf != NULL)
- {
- fgets(readbuf, sizeofreadbuf, gp->ptr[0]);
- return 1;
- }
-
- return -1;
- }
-
-
- /*
- * readCurveHeadGnuplot
- *
- * After a 'plot' or 'splot' command id issued to gnuplot, it responds
- * with a line containing the curve id # and the number of points (lines)
- * in this curve.
- *
- * Side Effects:
- * The converted integers are returned in as a side effect.
- *
- * Returns:
- * -1 if any input parameters were invalid
- * 1 presumed success
- *
- */
- int readCurveHeadGnuplot(GNUPLOT *gp, int *p_curveno, int *p_npts)
- {
- char buf[81];
-
- if (gp!=NULL && gp->ptr[0]!=NULL && p_curveno!=NULL && p_npts!=NULL)
- {
- /* this format should match what Gnuplot writes out */
- /*fscanf(gp->ptr[0],"Curve %d, %d points\n",p_curveno,p_npts);*/
- do
- fgets(buf, sizeof(buf),gp->ptr[0]);
- while (buf[0] == '\n');
- sscanf(buf,"Curve %d, %d points\n",p_curveno,p_npts);
-
- return 1;
- }
-
- return -1;
- }
-
- #define FREEALL_AND_LEAVE() \
- free((void*)r);free((void*)x);free((void*)y);free((void*)curve); \
- return NULL
-
- GPCurve *readCurveGnuplot(GNUPLOT *gp)
- {
- GPCurve *curve;
- int curveno, npts, cnt, i, is2d, n;
- char buf[81], *r;
- float *x,*y,*z;
-
- if (gp == NULL || gp->ptr[0] == NULL)
- return NULL;
-
- if ((curve = (GPCurve *) calloc(1, sizeof(GPCurve))) == NULL)
- return NULL;
-
- /* this format should match what Gnuplot writes out */
- /*fscanf(gp->ptr[0],"Curve %d, %d points\n",&curveno,&npts);*/
- do
- fgets(buf, sizeof(buf),gp->ptr[0]);
- while (buf[0] == '\n');
-
- sscanf(buf,"Curve %d, %d points\n",&curveno,&npts);
- if (npts < 1)
- {
- free((void *) curve);
- return NULL;
- }
-
- curve->curveno = curveno;
- curve->range = r = (char *) malloc(npts * sizeof(char));
- if (r == NULL)
- {
- free((void *) curve);
- return NULL;
- }
- curve->x = x = (float *) malloc(npts * sizeof(float));
- if (x == NULL)
- {
- free((void *) curve);
- free((void *) r);
- return NULL;
- }
- curve->y = y = (float *) malloc(npts * sizeof(float));
- if (y == NULL)
- {
- free((void *) curve);
- free((void *) r);
- free((void *) x);
- return NULL;
- }
-
- /* read the first line to see how many columns */
- fgets(buf, sizeof(buf), gp->ptr[0]);
- if ((n=count_items(buf)) == 4)
- {
- curve->is_2d = is2d = FALSE;
- curve->z = z = (float *) malloc(npts * sizeof(float));
- if (z == NULL)
- { FREEALL_AND_LEAVE(); }
- sscanf(buf,"%c x=%g y=%g z=%g\n",&r[0],&x[0],&y[0],&z[0]);
- }
- else if (n == 3)
- {
- curve->is_2d = TRUE;
- curve->z = NULL;
- sscanf(buf,"%c x=%g y=%g\n",&r[0],&x[0],&y[0]);
- }
- else
- {
- /* this shouldn't happen */
- fprintf(stderr,"readCurveGnuplot: count_items() not 3 or 4 "
- "(n=%d)\n", n);
- return NULL;
- }
- cnt = 1;
- for (i=1; i<npts && *buf != '\0'; i++)
- {
- fgets(buf, sizeof(buf), gp->ptr[0]);
- if(*buf != '\n' && *buf != '\0')
- {
- if (is2d) sscanf(buf,"%c x=%g y=%g\n",&r[i],&x[i],&y[i]);
- else sscanf(buf,"%c x=%g y=%g z=%g\n",&r[i],&x[i],&y[i],&z[i]);
- cnt++;
- }
- }
- curve->npts = cnt; /* _should_ equal npts! */
- return curve;
- }
-
-
-
- /*
- * readCurve2Gnuplot
- *
- * After a 'plot' command has been written and the curve heading read
- * back, this routine will convert all the points in the curve and
- * store them in the user's buffers.
- *
- * Inputs:
- * x[], y[] and range[] must be dimensioned to at least npoints!
- * range[] is a char buffer that contains on of:
- *
- * i - INRANGE, inside plot boundary
- * o - OUTRANGE, outside plot boundary, but defined
- * u - UNDEFINED, not defined at all
- *
- * range[] is optional; pass a NULL pointer if you don't want it.
- *
- * Returns:
- * Number of points converted and stored in x,y,range or
- * -1 if any input parameters were invalid
- *
- *
- */
- int readCurve2Gnuplot(GNUPLOT *gp, char *range, float *x, float *y, int npoints)
- {
- register int i;
- int cnt;
- char buf[81], c;
-
- if (gp != NULL && gp->ptr[0] != NULL && x != NULL && y != NULL)
- {
- cnt = 0;
-
- if (range != NULL)
- {
- for (i=0; i<npoints; i++)
- {
- fgets(buf, sizeof(buf), gp->ptr[0]);
- if(*buf != '\n' && *buf != '\0')
- {
- sscanf(buf,"%c x=%g y=%g\n",&range[i],&x[i],&y[i]);
- cnt++;
- }
- }
- }
- else /* throw range away */
- {
- for (i=0; i<npoints; i++)
- {
- fgets(buf, sizeof(buf), gp->ptr[0]);
- if(*buf != '\n' && *buf != '\0')
- {
- sscanf(buf,"%c x=%g y=%g\n",&c,&x[i],&y[i]);
- cnt++;
- }
- }
- }
- return cnt;
- }
-
- return -1;
- }
-
-
-
- /*
- * readCurve3Gnuplot
- *
- * After an 'splot' command has been written and the curve heading read
- * back, this routine will convert all the points in the curve and
- * store them in the user's buffers.
- *
- * Inputs:
- * x[], y[], z[] and range[] must be dimensioned to at least npoints!
- * range[] is a char buffer that contains on of:
- *
- * i - INRANGE, inside plot boundary
- * o - OUTRANGE, outside plot boundary, but defined
- * u - UNDEFINED, not defined at all
- *
- * range[] is optional; pass a NULL pointer if you don't want it.
- *
- * Returns:
- * Number of points converted and stored in x,y,range or
- * -1 if any input parameters were invalid
- *
- *
- */
- int readCurve3Gnuplot(GNUPLOT *gp, char *range, float *x, float *y, float *z,
- int npoints)
- {
- register int i;
- int cnt;
- char buf[81], c;
-
- if (gp != NULL && gp->ptr[0] != NULL && x != NULL && y != NULL &&
- z != NULL)
- {
- cnt = 0;
-
- if (range != NULL)
- {
- for (i=0; i<npoints; i++)
- {
- fgets(buf, sizeof(buf), gp->ptr[0]);
- if(*buf != '\n' && *buf != '\0')
- {
- sscanf(buf,"%c x=%g y=%g\n",&range[i],&x[i],&y[i],
- &z[i]);
- cnt++;
- }
- }
- }
- else /* throw range away */
- {
- for (i=0; i<npoints; i++)
- {
- fgets(buf, sizeof(buf), gp->ptr[0]);
- if(*buf != '\n' && *buf != '\0')
- {
- sscanf(buf,"%c x=%g y=%g\n",&c,&x[i],&y[i],&z[i]);
- cnt++;
- }
- }
- }
- return cnt;
- }
-
- return -1;
- }
-
-
-
- /*
- * closeGnuplot
- *
- * Shuts down the pipes to the gnuplot process.
- * If quitflag is non-zero, a 'quit' command will be issued to gnuplot.
- *
- * Returns:
- * 1 presumed success at closing the connection
- * 0 error in pclose_ioe()
- * -1 if any input parameters were invalid
- *
- */
- int closeGnuplot(GNUPLOT *gp, int quitflag)
- {
- if (gp != NULL && gp->ptr[1] != NULL)
- {
- if (quitflag) fputs("quit\n",gp->ptr[1]);
- if(pclose_ioe(gp->ptr) == -1)
- return 0;
- return 1;
- }
-
- return -1;
- }
-
-